package my.edu.common.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;


@Configuration
public class RedisConfig {
    @Resource
    private RedisConnectionFactory factory;

    //对象与json字符串之间的转换，使用fasterxml的jackson替代原有的JdkSerializationRedisSerializer
    /*
    ObjectMapper 设置：
    setVisibility：
    设置字段的可见性为 ANY，允许序列化/反序列化所有字段（包括 private 字段）。
    activateDefaultTyping：
    启用类型信息，以确保反序列化时能够正确识别对象类型。
    使用 LaissezFaireSubTypeValidator 提高安全性，限制允许的类型范围。
    配置 DefaultTyping.NON_FINAL，表示仅对非 final 类型启用类型信息（final 类型如 String 会被排除）。
    */
//    @Bean
//    public Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer() {
//        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
//        ObjectMapper objectMapper = new ObjectMapper();
//        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
//        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
//
//        return jackson2JsonRedisSerializer;
//    }


//    @Bean
//    public GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer() {// 使用通用的 Jackson 序列化器
//        GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer();
//        return serializer;
//
//    }

    /*
    KeySerializer 和 ValueSerializer：

    KeySerializer：
    使用 StringRedisSerializer，将 Redis 的键序列化为字符串。
    这是常见的键序列化方式，便于阅读和管理。
    ValueSerializer：
    使用前面定义的 Jackson2JsonRedisSerializer，以 JSON 格式序列化值。
    HashKeySerializer 和 HashValueSerializer：

    类似地，设置 Hash 类型的键和值的序列化方式。
    Hash 是 Redis 中的一个数据结构，用于存储键值对。
    连接工厂：

    调用 redisTemplate.setConnectionFactory(factory)，将 Redis 的连接工厂注入模板中。
    * */
    @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);

        // 配置 ObjectMapper
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new JavaTimeModule()); // 支持 Java 8 日期时间类型
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); // 禁用时间戳格式
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); // 忽略未知字段
        objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL); // 启用类型信息

        // 配置序列化器
        redisTemplate.setKeySerializer(new StringRedisSerializer()); // 键字符串序列化
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer(objectMapper)); // 值json序列化
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer(objectMapper));

        return redisTemplate;
    }
}
